import openpyxl
import re

from common import encry_decry
from path_file import path_file

wb = openpyxl.load_workbook(filename=f"{path_file}/data/mtxshop_keyword.xlsx")
# # 获取某个sheet工作表数据
# sheet_data = wb["测试用例集合"]
# print(sheet_data)
# # 遍历sheet_data，得到所有结果
# lines_count = sheet_data.max_row  # max_row表示所有行数
# cols_count = sheet_data.max_column # max_column 表示所有列数
# for i in range(2,lines_count+1): # 在openpyxl库 行和列的起始都是从1开始
#     for j in range(1,cols_count+1):
#         cell = sheet_data.cell(row=i, column=j).value
#         print(cell)

def get_casesuitename():
    """
    获取要执行的测试集合名称
    :return:
    """
    case_suite_names = []  # 用来存储得到的要执行的测试集合名称
    sheet_data = wb['测试用例集合']
    lines_count = sheet_data.max_row  # 总行数
    cols_count = sheet_data.max_column  # 总列数
    for l in range(2, lines_count + 1):  # 在openpyxl库行和列的起始都是从1开始
        # 判断是否执行列的值如果是y则将其加到case_suite_names
        if sheet_data.cell(l, 2).value == 'y':
            cell = sheet_data.cell(l, 1).value
            case_suite_names.append(cell)
    return case_suite_names


def get_variables():
    """
    获取所有全局变量
    :return:
    """
    sheet_data = wb['全局变量']
    variables = {}  # 用来存储得到的所有的变量数据
    lines_count = sheet_data.max_row  # 总行数
    cols_count = sheet_data.max_column  # 总列数
    for l in range(2, lines_count + 1):
        key = sheet_data.cell(l, 1).value  # 第一列是变量名称，作为key
        value = sheet_data.cell(l, 2).value  # 第二列是变量值，作为value
        variables[key] = value
    return variables


def get_all_apis_default():
    """
    获取所有接口的默认参数
    :return:
    """
    sheet_data = wb['接口默认参数']
    apis_default_data = {}  # 用来存储得到的所有的接口默认数据
    lines_count = sheet_data.max_row  # 总行数
    cols_count = sheet_data.max_column  # 总列数
    for l in range(2, lines_count + 1):
        key = sheet_data.cell(l, 1).value  # 第一列是变量名称，作为key
        value = sheet_data.cell(l, 2).value  # 第二列是变量值，作为value
        apis_default_data[key] = value
    return apis_default_data


def read_testcases(case_suite_name):
    """
    根据要执行的测试集合名称去读取对应的sheet工作中的所有测试用例
    :param case_suite_name:
    :return:
    """
    sheet_data = wb[case_suite_name]
    lines_count = sheet_data.max_row  # 总行数
    cols_count = sheet_data.max_column  # 总列数
    # 思考：读出来的所有行，如何去存储多行数据代表一条用例的情况，规则是测试用例名称相同的行会被认为是一条测试用例
    """
    {
        "添加购物车-添加成功":[
            ['apiname','url','method','headers','testparams','响应提取','状态码断言','响应断言'],
            ['apiname','url','method','headers','testparams','响应提取','状态码断言','响应断言'],
            ['apiname','url','method','headers','testparams','响应提取','状态码断言','响应断言']
        ],
        "添加购物车-商品id不存在":[
            ['apiname','url','method','headers','testparams','响应提取','状态码断言','响应断言'],
            ['apiname','url','method','headers','testparams','响应提取','状态码断言','响应断言']
        ]
    }
    """
    cases_info = {}  # 用来存储当前测试集合中得到的所有数据的，就是上面的那种结构
    for l in range(2, lines_count + 1):
        case_name = sheet_data.cell(l, 1).value
        line = []  # 存储从接口名称这一列开始往后的当前行的数据
        for c in range(2, cols_count + 1):
            cell = sheet_data.cell(l, c).value
            if cell is None:  # 如果单元格内容是空的，给他赋值空字符串，方便后续处理
                cell = ''
            line.append(cell)
        # 接下来要把用例名称和用例数据添加到cases_info
        if case_name in cases_info:  # 如果当前用例名称已经在cases_info中了，那么就是追加当前行到他对应的数据中去
            cases_info[case_name].append(line)
        else:
            cases_info[case_name] = [line]
    return cases_info


# 整合所有的要执行的测试集合里的用例，把他们拼装在一起，形成符合pytest参数化需要的数据格式
# [[],[],[],[]]
def get_all_cases():
    case_suite_names = get_casesuitename()  # 获取所有要执行的测试集合名称
    """
    [
        ['添加购物车-添加成功',
            [
                ['apiname','url','method','headers','testparams','响应提取','状态码断言','响应断言'],
                ['apiname','url','method','headers','testparams','响应提取','状态码断言','响应断言'],
                ['apiname','url','method','headers','testparams','响应提取','状态码断言','响应断言']
            ]
        ],
        ['添加购物车-商品id不存在',[
                ['apiname','url','method','headers','testparams','响应提取','状态码断言','响应断言'],
                ['apiname','url','method','headers','testparams','响应提取','状态码断言','响应断言'],
                ['apiname','url','method','headers','testparams','响应提取','状态码断言','响应断言']
            ]
        ]

    ]

    """
    test_cases = []  # 用来存储所有的测试用例的
    for case_suite_name in case_suite_names:
        suite_cases = read_testcases(case_suite_name)  # 获取某个测试集合里的所有用例
        for key, value in suite_cases.items():
            # key其实就是用例名称
            # value其实就是测试用例名称对应的多行数据
            cur_case = [key, value]  # ['测试用例1',[[],[],[]]]
            test_cases.append(cur_case)
    return test_cases


def regx_sub(string, vars_dict: dict):
    """
    匹配动态变量，并完成变量数据替换
    :param string: 目标数据
    :param vars_dict: vars_dict是全局变量字典
    :return:
    """
    # 通过正则查找
    res = re.findall(r'\$\{([A-Za-z_]+?)\}', string)
    print(res)
    for var_name in res:
        print(var_name)
        value = vars_dict[var_name]  # 从全局变量中得到对应的值
        # 把value替换到原位置上
        # 字符串替换
        # string = string.replace(f'${{{var_name}}}',str(value))
        # 使用正则的替换方法
        string = re.sub(r'\$\{' + var_name + r'\}', str(value), string)
    return string


def regx_exec(string):
    """
    匹配字符串中的动态函数，并完成数据替换
    :param string:
    :return:
    """
    # 通过正则查找
    res = re.findall(r'\$\{\{(.+?)\((.+?)\)\}\}', string)
    print(res)
    for func in res:
        func_name = func[0]
        func_params = func[1]
        if hasattr(encry_decry, func_name):  # 如果函数在encry_decry模块里
            func_method = getattr(encry_decry, func_name)  # 从encry_decry里得到函数对象
            value = func_method(func_params)  # 执行函数，得到结果
            string = string.replace(f'${{{{{func_name}({func_params})}}}}', str(value))
    return string


if __name__ == '__main__':
    print(get_casesuitename())
    print(get_variables())
    print(get_all_apis_default())
    print(read_testcases('添加购物车测试集合'))
    print(get_all_cases())
    # \$\{([A-Za-z_]+?)\}
    # \$\{\{(.+?)\((.+?)\)\}\}

    s = '${sellerHost}/seller/goods'
    vars_dict = get_variables()
    print(regx_sub(s, vars_dict))

    s = '"password":"${{md5(abc123456)}}"'
    print(regx_exec(s))